/**
* @file       st7735.h
* @author     mz8023yt
* @email      mz8023yt@163.com
* @version    V1.0
* @date       2022-03-13
* @brief      st7735 lcd driver
*/

#ifdef __cplusplus
extern "C"
{
#endif

#include "st7735.h"
#include <stdint.h>

/**
	* @brief 初始化配置参数列表
	*
	*/
struct cmds init_cmds[] = {
	{0x11, {0}, 0},
	{0x21, {0}, 0},
	{0xB1, {0x05, 0x3A, 0x3A}, 3},
	{0xB2, {0x05, 0x3A, 0x3A}, 3},
	{0xB3, {0x05, 0x3A, 0x3A, 0x05, 0x3A, 0x3A}, 6},
	{0xB4, {0x03}, 1},
	{0xC0, {0x62, 0x02, 0x04}, 3},
	{0xC1, {0xC0}, 1},
	{0xC2, {0x0D, 0X00}, 2},
	{0xC3, {0x8D, 0x6A}, 2},
	{0xC4, {0x8D, 0xEE}, 2},
	{0xC5, {0x0E}, 1},
	{0xE0, {0x02, 0x1C, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2D, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10}, 16},
	{0xE1, {0x03, 0x1D, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10}, 16},
	{0x3A, {0x05}, 1},
	{0x36, {0x08}, 1},
	{0x29, {0}, 0},
	{0x00, {0}, 0xff},
};

/**
	* @brief 屏幕初始化
	*
	* @param lcd
	*/
void st7735_init(struct st7735 *lcd)
{
	uint32_t n = 0;

	lcd->ops.pin.rst(LOW);
	lcd->ops.time.msleep(20);
	lcd->ops.pin.rst(HIGH);
	lcd->ops.time.msleep(120);

	while (init_cmds[n].nums != 0xff) {
		lcd->ops.pin.dc(LOW);
		lcd->ops.spi.write(&init_cmds[n].cmd, 1);

		if (!init_cmds[n].nums) {
			n++;
			continue;
		}

		lcd->ops.pin.dc(HIGH);
		lcd->ops.spi.write(init_cmds[n].dats, init_cmds[n].nums);
		n++;
	}

	lcd->ops.pin.bl(HIGH);
}

/**
	* @brief 画点函数
	*
	* @param lcd
	* @param x
	* @param y
	* @param color
	*/
void st7735_point_draw(struct st7735 *lcd, uint8_t x, uint8_t y, uint16_t color)
{
	uint8_t cmds = 0x00;
	uint8_t dats[4] = {0x00, 0x00, 0x00, 0x00};

	/* Column Address Set */
	cmds = 0x2A;
	dats[1] = x + lcd->cfg.fix.xshift;
	dats[3] = x + lcd->cfg.fix.xshift;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Row Address Set */
	cmds = 0x2B;
	dats[1] = y + lcd->cfg.fix.yshift;
	dats[3] = y + lcd->cfg.fix.yshift;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Memory Write */
	cmds = 0x2C;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	dats[0] = color >> 8;
	dats[1] = color & 0xff;
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 2);
}

/**
	* @brief 矩形填充
	*
	* @param lcd
	* @param x1
	* @param y1
	* @param x2
	* @param y2
	* @param color
	*/
void st7735_rect_fill(struct st7735 *lcd, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t *color)
{
	uint8_t cmds = 0x00;
	uint8_t dats[4] = {0x00, 0x00, 0x00, 0x00};

	/* Column Address Set */
	cmds = 0x2A;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	dats[1] = x1 + lcd->cfg.fix.xshift;
	dats[3] = x2 + lcd->cfg.fix.xshift;
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Row Address Set */
	cmds = 0x2B;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	dats[1] = y1 + lcd->cfg.fix.yshift;
	dats[3] = y2 + lcd->cfg.fix.yshift;
	lcd->ops.spi.write(dats, 4);

	/* Memory Write */
	cmds = 0x2C;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);

	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write((uint8_t *)color, (y2 - y1 + 1) * (x2 - x1 + 1) * 2);
}

void st7735_rect_fill_color(struct st7735 *lcd, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
	int i = 0;
	uint8_t cmds = 0x00;
	uint8_t dats[4] = {0x00, 0x00, 0x00, 0x00};
	uint32_t cnts = 0;

	/* Column Address Set */
	cmds = 0x2A;
	dats[0] = (x1 + lcd->cfg.fix.xshift) >> 8;
	dats[1] = (x1 + lcd->cfg.fix.xshift) & 0xff;
	dats[2] = (x2 + lcd->cfg.fix.xshift) >> 8;
	dats[3] = (x2 + lcd->cfg.fix.xshift) & 0xff;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Row Address Set */
	cmds = 0x2B;
	dats[0] = (y1 + lcd->cfg.fix.yshift) >> 8;
	dats[1] = (y1 + lcd->cfg.fix.yshift) & 0xff;
	dats[2] = (y2 + lcd->cfg.fix.yshift) >> 8;
	dats[3] = (y2 + lcd->cfg.fix.yshift) & 0xff;
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(dats, 4);

	/* Memory Write */
	cmds = 0x2C;
	cnts = (x2 - x1 + 1) * (y2 - y1 + 1);
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmds, 1);
	lcd->ops.pin.dc(HIGH);
	for (i = 0; i < cnts; i++) {
		dats[0] = color >> 8;
		dats[1] = color & 0xff;
		lcd->ops.spi.write(dats, 2);
	}
}

void st7735_rotate_set(struct st7735 *lcd, enum rotate_t rotate)
{

	int width = 0;
	int height = 0;
	int xshift = 0;
	int yshift = 0;
	uint8_t cmd = 0x36;
	uint8_t dat = 0x00;

	if (ROTATE_0 == lcd->cfg.var.orien || ROTATE_180 == lcd->cfg.var.orien) {
		width = lcd->cfg.fix.width;
		height = lcd->cfg.fix.height;
		xshift = lcd->cfg.fix.xshift;
		yshift = lcd->cfg.fix.yshift;
	} else {
		width = lcd->cfg.fix.height;
		height = lcd->cfg.fix.width;
		xshift = lcd->cfg.fix.yshift;
		yshift = lcd->cfg.fix.xshift;
	}

	switch (rotate)
	{
	case ROTATE_0:
		dat = 0x00;
		lcd->cfg.var.orien = ROTATE_0;
		lcd->cfg.fix.width = width;
		lcd->cfg.fix.height = height;
		lcd->cfg.fix.xshift = xshift;
		lcd->cfg.fix.yshift = yshift;
		break;
	case ROTATE_90:
		lcd->cfg.var.orien = ROTATE_90;
		lcd->cfg.fix.width = height;
		lcd->cfg.fix.height = width;
		lcd->cfg.fix.xshift = yshift;
		lcd->cfg.fix.yshift = xshift;
		dat = 0x60;
		break;
	case ROTATE_180:
		lcd->cfg.var.orien = ROTATE_180;
		lcd->cfg.fix.width = width;
		lcd->cfg.fix.height = height;
		lcd->cfg.fix.xshift = xshift;
		lcd->cfg.fix.yshift = yshift;
		dat = 0xC0;
		break;
	case ROTATE_270:
		lcd->cfg.var.orien = ROTATE_270;
		lcd->cfg.fix.width = height;
		lcd->cfg.fix.height = width;
		lcd->cfg.fix.xshift = yshift;
		lcd->cfg.fix.yshift = xshift;
		dat = 0xA0;
		break;

	default:
		dat = 0x00;
		break;
	}

	dat |= 0x08;

	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmd, 1);
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(&dat, 1);
}

#ifdef __cplusplus
}
#endif
